import java.io.FileReader;
import java.io.IOException;
import java.io.LineNumberReader;
import java.util.LinkedList;

/**
 * Authors - Oren Bracha, Rony Lahav & Yehuda Eterman
 * This class handles the input.txt file by parsing it to its different regions and getting the content
 */

public class InputFileManager {
	static String environmentSection;
	static String peerDataSection;
	static String commandsSection;
	static InputFileManager instance;
	private final static String VAR_UPDATEDATA = "updatedata";
	
	//Singleton CTOR - reads the file and divides it into environment, data and commands sections 
	private InputFileManager(){
		//if we got an IO error it means we couldn't read the file so we can't actually run and we return null
		try {
			LineNumberReader reader = new LineNumberReader(new FileReader(proj350.inputFilePath));
			
			StringBuilder sb = new StringBuilder();
			
			String line = reader.readLine();
			while (line != null) {
				sb.append(line);
				sb.append(MessageCenter.newline);
				line = reader.readLine();
			}
			
			int index = sb.toString().indexOf('%');
			environmentSection = sb.toString().substring(0, index);
			
			index = sb.toString().indexOf("PEERDATA");
			peerDataSection = sb.toString().substring(index, sb.toString().indexOf('%', index));
			
			index = sb.toString().indexOf("COMMANDS");
			commandsSection = sb.toString().substring(index+9);
			//we deal with SHUTDOWN command as a usual command so we turn it to a normal command format
			commandsSection = commandsSection.replaceAll("SHUTDOWN", "\\&SHUTDOWN");
		}
		catch (IOException e) {
			instance = null;
		}
	}
	
	//Singleton
	public static InputFileManager getInstance() {
		instance = new InputFileManager();
		return instance;
	}
	
	//returns a specific Environment value
	public String getEnvironmentValue(String field) {
		int firstIndex = environmentSection.indexOf("$"+field+":");
		int middleIndex = environmentSection.indexOf(':', firstIndex);
		int endLineIndex = environmentSection.indexOf("\n", middleIndex);
		
		String strEnvVar = environmentSection.substring(middleIndex+1, endLineIndex);
		if (strEnvVar.endsWith("\r"))
			strEnvVar=strEnvVar.substring(0, strEnvVar.length()-1);
		return strEnvVar;
	}
	
	//returns a specific Data value
	public String getPeerDataValue(String field) {
		int firstIndex = peerDataSection.indexOf("$"+field+":");
		int middleIndex = peerDataSection.indexOf(':', firstIndex);
		int endLineIndex = peerDataSection.indexOf("\n", middleIndex);
		
		String strPeerDataVar = peerDataSection.substring(middleIndex+1, endLineIndex);
		if (strPeerDataVar.endsWith("\r"))
			strPeerDataVar=strPeerDataVar.substring(0, strPeerDataVar.length()-1);
		return strPeerDataVar;
	}
	
	//parses the commands and returns all of them as a list of commands by creating the relevant command class for each of them
	public LinkedList<ICmd> getCommandsValues() {
		LinkedList<ICmd> commands = new LinkedList<ICmd>();
		String[] splittedCmds = commandsSection.toLowerCase().split("\\&");
		for (int i=0;i<splittedCmds.length;++i){
			if (splittedCmds[i].endsWith("\n"))
				splittedCmds[i]=splittedCmds[i].substring(0, splittedCmds[i].length()-1);
			if (splittedCmds[i].endsWith("\r"))
				splittedCmds[i]=splittedCmds[i].substring(0, splittedCmds[i].length()-1);
			/*updatedata($parameter1:value1,...,$parameterN:valueN)
			 * has several possible parameters that are parsed into a link list of parameter+value String arrays*/
			if (splittedCmds[i].startsWith(VAR_UPDATEDATA)){
				String[] splittedVars = splittedCmds[i].split("\\(\\$");
				String command = "($" + splittedVars[1];
				splittedVars = splittedVars[1].substring(0, splittedVars[1].length()-1).split(",\\$");
				LinkedList<String[]> vars = new LinkedList<String[]>();
				for (int j=0;j<splittedVars.length;++j){
					String[] params = splittedVars[j].split(":");
					vars.add(params);
				}
				commands.add(new CmdUpdateData(vars, command));
			}
			else{
				boolean done=false;
				String[] command = splittedCmds[i].split(":");
				//run:[Time Parameter]
				if (!done && command[0].equals("run")) {
					commands.add(new CmdRun(command[1], "(" + command[1] + ")"));
					done=true;
				}
				//sleep:[Time Parameter]
				if (!done && command[0].equals("sleep")) {
					commands.add(new CmdSleep(command[1], "(" + command[1] + ")"));
					done=true;
				}
				//deletedb:0 or deletedb:1 
				if (!done && command[0].equals("deletedb")) {
					commands.add(new CmdDeleteDB(command[1], "(" + command[1] + ")"));
					done=true;
				}
				//shutdown
				if (!done && command[0].equals("shutdown")) {
					commands.add(new CmdShutdown(""));
					done=true;
				}
			}
		}
		return commands;
	}

}
